// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:构建arm64和linux 
// +构建arm64，linux 

package cpu

// HWCap可以由archauxv初始化，初始化后不应更改
// 。
var HWCap uint

// HWCAP位。这些都是Linux公开的。
const (
	hwcap_AES     = 1 << 3
	hwcap_PMULL   = 1 << 4
	hwcap_SHA1    = 1 << 5
	hwcap_SHA2    = 1 << 6
	hwcap_CRC32   = 1 << 7
	hwcap_ATOMICS = 1 << 8
	hwcap_CPUID   = 1 << 11
)

func hwcapInit(os string) {
	// HWCap由辅助向量中的运行时填充。
	// 使用HWCap信息，因为在旧linux内核的用户空间中不支持读取aarch64系统寄存器
	// 。
	ARM64.HasAES = isSet(HWCap, hwcap_AES)
	ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL)
	ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1)
	ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2)
	ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32)
	ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID)

	// 三星S9+内核报告支持原子，但并非所有内核
	// 实际上都支持原子，导致SIGILL。见第28431期。
	// TODO（elias.naur）：仅在android上禁用对坏芯片组的优化。
	ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) && os != "android"

	// 检查是否在NeoverseN1上执行，为此，
	// 检查AUXV中的CPUID位。getMIDR函数执行一条
	// 指令，该指令通常是非法指令，但它是被内核捕获的
	// 值，经过清理后返回。如果没有
	// CPUID位，内核将不会捕获指令，进程
	// 将以SIGILL终止。
	if ARM64.HasCPUID {
		midr := getMIDR()
		part_num := uint16((midr >> 4) & 0xfff)
		implementor := byte((midr >> 24) & 0xff)

		if implementor == 'A' && part_num == 0xd0c {
			ARM64.IsNeoverseN1 = true
		}
		if implementor == 'A' && part_num == 0xd40 {
			ARM64.IsZeus = true
		}
	}
}

func isSet(hwc uint, value uint) bool {
	return hwc&value != 0
}
